﻿using NLog;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows;

namespace IOA.MES.Client.Common.SocketUtils
{

    public delegate void OnTcpStatusChange(bool connected);
    public delegate void OnDataReceived(List<byte> data);
    public class SocketClient
    {
        private IPEndPoint endpoint = null;
        private Window window = null;
        private TcpClient client;
        private NetworkStream networkStream;
        private bool isHeartBeating = false;
        private OnTcpStatusChange onStatusChange;
        private OnDataReceived onDataReceived;
        private List<byte> heartBeatData;
        private int headBeatMilSecs;
        public SocketClient(Window window, string ipAddress, int port,
            OnTcpStatusChange onStatusChange, OnDataReceived onDataReceived,
            List<byte> heartBeatData, int headBeatMilSecs)
        {
            this.window = window;
            this.onStatusChange = onStatusChange;
            this.onDataReceived = onDataReceived;
            this.heartBeatData = heartBeatData;
            this.headBeatMilSecs = headBeatMilSecs;
            endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
        }

        /// <summary>
        /// 连接到服务端
        /// </summary>
        public void Connect()
        {
            try
            {
                client = new TcpClient();
                CommonMessage.Log(LogLevel.Debug, $"【{client.Client.LocalEndPoint}】准备连接远程TCP：{endpoint}");
                client.Connect(endpoint);
                CommonMessage.Log(LogLevel.Debug, $"【{client.Client.LocalEndPoint}】连接远程TCP成功：{endpoint}");
                if (onStatusChange != null)
                {
                    try
                    {
                        onStatusChange(true);
                    }
                    catch (Exception ex)
                    {
                        CommonMessage.Log(LogLevel.Debug, $"onStatusChange异常：{ex.Message}", ex);
                    }
                }
                if (!isHeartBeating)
                {
                    isHeartBeating = true;
                    Thread thread = new Thread(heartBeat);
                    thread.IsBackground = true;
                    thread.Start();
                }

                networkStream = client.GetStream();
                byte[] TempBytes = new byte[1024];
                networkStream.BeginRead(TempBytes, 0, TempBytes.Length, new AsyncCallback(AsynReceiveData), TempBytes);
            }
            catch (Exception ex)
            {
                CommonMessage.Log(LogLevel.Fatal, "Connect Error", ex);
                window.Dispatcher.BeginInvoke(new Action(() =>
                {
                    CommonMessage.Alert(window, $"无法连接TCP服务:{endpoint}");
                }));
            }
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        public void Close()
        {
            if (client?.Connected == true)
            {
                client.Close();
                onStatusChange(false);
            }
        }

        /// <summary>
        /// 采用线程间隔一秒发送数据，防止界面卡死
        /// </summary>
        private void heartBeat()
        {
            while (isHeartBeating)
            {
                if (!client.Connected)
                {
                    CommonMessage.Log(LogLevel.Debug, $"TCP已断开：{endpoint}");
                    if (onStatusChange != null)
                    {
                        onStatusChange(false);
                    }

                    Connect();
                }
                else if ((heartBeatData ?? new List<byte>()).Count > 0)
                {
                    Send(heartBeatData);
                }
                Thread.Sleep(headBeatMilSecs);
            }
        }

        /// <summary>
        /// 发送报文
        /// </summary>
        public void Send(List<byte> data)
        {
            CommonMessage.Log(LogLevel.Debug, $"准备发送报文：{ByteUtils.HexToString(data.ToArray())}");
            if (client.Connected)
            {
                client.Client.Send(data.ToArray());
                CommonMessage.Log(LogLevel.Debug, $"报文发送成功：{ByteUtils.HexToString(data.ToArray())}");
            }
            else
            {
                CommonMessage.Log(LogLevel.Debug, $"TCP不可用，取消发送报文：{ByteUtils.HexToString(data.ToArray())}");
            }
        }

        /// <summary>
        /// 异步接受数据
        /// </summary>
        /// <param name="iar"></param>
        public void AsynReceiveData(IAsyncResult ar)
        {
            var stream = client.GetStream();
            int numberOfReadBytes = 0;
            try
            {
                numberOfReadBytes = stream.EndRead(ar);
            }
            catch
            {
                numberOfReadBytes = 0;
            }

            if (numberOfReadBytes <= 0)
            {
                return;
            }

            byte[] buffer = (byte[])ar.AsyncState;
            byte[] receivedBytes = new byte[numberOfReadBytes];
            Buffer.BlockCopy(buffer, 0, receivedBytes, 0, numberOfReadBytes);

            var result = ByteUtils.HexToString(receivedBytes);
            CommonMessage.Log(LogLevel.Debug, $"接收报文：{result}");

            if (onDataReceived != null)
            {
                try
                {
                    onDataReceived(new List<byte>(receivedBytes));
                }
                catch (Exception ex)
                {
                    CommonMessage.Log(LogLevel.Fatal, $"接收报文处理异常：{ex.Message}", ex);
                }
            }

            stream.BeginRead(buffer, 0, buffer.Length, AsynReceiveData, buffer);
        }
    }
}
